/**
 * @file
 * @author Filipe Mutz
 *
 * @section DESCRIPTION
 *
 */
#include "image.h"

namespace brain
{
	namespace image
	{
		Image::Image()
		{
			srand(time(NULL));

			_img = NULL;
			sprintf(_img_id, "%031d", rand());
		}


		Image::Image(Image &img)
		{
			_img = cvCreateImage(cvSize(img._img->width, img._img->height), img._img->depth, img._img->nChannels);
			cvCopy(img._img, _img, NULL);
		}


		Image::~Image()
		{
			if (_img != NULL)
				cvReleaseImage(&_img);
		}


		Image&
		Image::operator=(const Image &img)
		{
			// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
			// TODO: check if the images have not the same type
			// and size to avoid unecessary free and allocs!
			// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

			if (_img != NULL)
				cvReleaseImage(&_img);

			_img = cvCreateImage(cvSize(img._img->width, img._img->height), img._img->depth, img._img->nChannels);

			cvCopy(img._img, _img, NULL);
			return (*this);
		}


		void
		Image::read(char *filename, int format)
		{
			_img = cvLoadImage(filename, format);

			if (_img == NULL)
				exit(printf("Error: Failed to load the image \"%s\"\n", filename));
		}


		int
		Image::get_pixel_position(int i, int j)
		{
			return (i * _img->widthStep + _img->nChannels * j);
		}


		void
		Image::save(char *filename) const
		{
			cvSaveImage(filename, _img, NULL);
		}


		int
		Image::show() const
		{
			cvShowImage(_img_id, _img);
			cvWaitKey(-1);

			return 0;
		}


		int
		Image::show(int delay) const
		{
			cvShowImage(_img_id, _img);

			if ((cvWaitKey(delay) & 255) == 27)
				return 1;
			else
				return 0;
		}


		int
		Image::width() const
		{
			return _img->width;
		}


		int
		Image::height() const
		{
			return _img->height;
		}


		GrayscaleImage::GrayscaleImage()
		{
		}


		GrayscaleImage::~GrayscaleImage()
		{
		}


		void
		GrayscaleImage::read(char *filename)
		{
			Image::read(filename, CV_LOAD_IMAGE_GRAYSCALE);
		}


		Gray
		GrayscaleImage::get (int i, int j)
		{
			int p = get_pixel_position(i, j);
			unsigned char pixel_value = (_img->imageData[p]);

			Gray gray;
			gray.intensity = (int) pixel_value;

			return gray;
		}


		void
		GrayscaleImage::set(int i, int j, Gray gray)
		{
			int p = get_pixel_position(i, j);
			_img->imageData[p] = (unsigned char) gray.intensity;
		}


		void
		GrayscaleImage::draw_point(int i, int j)
		{
			int radius = _img->width / 320;

			if (radius <= 1)
				radius = 2;

			cvCircle(_img, cvPoint(j, i), radius, cvScalar(0, 0, 255, 0), 1, 1, 0);
		}


		ColorImage::ColorImage()
		{
		}


		ColorImage::~ColorImage()
		{
		}


		void
		ColorImage::read(char *filename)
		{
			Image::read(filename, CV_LOAD_IMAGE_COLOR);
		}


		Color
		ColorImage::get (int i, int j)
		{
			int p = get_pixel_position(i, j);

			Color color;

			color.blue_intensity = _img->imageData[p + 0];
			color.green_intensity = _img->imageData[p + 1];
			color.red_intensity = _img->imageData[p + 2];

			return color;
		}


		void
		ColorImage::set(int i, int j, Color color)
		{
			int p = get_pixel_position(i, j);

			_img->imageData[p + 0] = color.blue_intensity;
			_img->imageData[p + 1] = color.green_intensity;
			_img->imageData[p + 2] = color.red_intensity;
		}


		void
		ColorImage::draw_point(int i, int j)
		{
			int radius = _img->width / 320;

			if (radius <= 1)
				radius = 2;

			cvCircle(_img, cvPoint(j, i), radius, cvScalar(0, 0, 255, 0), 1, 1, 0);
		}
	}
}
